package com.sztx.pay.center.rpc.component;

import java.util.Date;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.sztx.pay.center.common.util.ConfigUtil;
import com.sztx.pay.center.common.util.Constance;
import com.sztx.pay.center.common.util.ObjectUtil;
import com.sztx.pay.center.common.util.StringUtil;
import com.sztx.pay.center.common.util.ValidateUtil;
import com.sztx.pay.center.core.service.AccountService;
import com.sztx.pay.center.core.service.UserInfoService;
import com.sztx.pay.center.dataaccess.domain.UserActDO;
import com.sztx.pay.center.dataaccess.domain.UserBindCardDO;
import com.sztx.pay.center.dataaccess.domain.UserInfoDO;
import com.sztx.pay.center.rpc.api.domain.TradeBaseRequest;
import com.sztx.pay.center.rpc.api.domain.TradeResponse;
import com.sztx.pay.risk.rpc.api.PayRiskService;
import com.sztx.pay.risk.rpc.api.domain.RiskParam;
import com.sztx.pay.risk.rpc.api.domain.TradeType;
import com.sztx.se.common.exception.BusinessException;
import com.sztx.se.common.util.secret.MD5Util;
import com.sztx.se.rpc.dubbo.client.DubboClientFactory;


public abstract class TradeService {	
	protected Logger logger = LoggerFactory.getLogger(this.getClass());
		
	protected UserBindCardDO payerBindCardInfo;
	
	protected UserBindCardDO payeeBindCardInfo;
	
	protected UserActDO payerActInfo;
	
	protected UserActDO payeeActInfo;
	
	@Autowired
	protected AccountService accountService;
	
	@Autowired
	private DubboClientFactory dubboConsumerFactory;
	
	@Autowired
	private UserInfoService userInfoService;
	
	public TradeResponse executeTade(TradeBaseRequest request){
		
		Map<String, String> map = ObjectUtil.transBean2Map(request);
		
		if (map == null || map.isEmpty()) {
			throw new BusinessException("请求参数不能为空");
		}
		
		//请求验签
		checkSign(map);
		
		//校验请求公共请求参数
		checkPublicParam(map);
		
		//校验请求私用请求参数
		checkPrivateParam(map);
		
		//检验订单是否重复
		boolean flag = isRepeatOrder(map);
		
		if (flag) { //订单重复请求			
			throw new BusinessException("订单["+request.getOrderId()+"]不能重复提交");
			
		}		
		
		//获取支付者账户信息
		this.payerActInfo = getPayerActInfo(request);
		
		//获取接收方账户信息
		this.payeeActInfo = getPayeeActInfo(request);
		
				
		//获取支付方绑卡信息并校验
		String bindNo = map.get("bindNo");
		if (StringUtils.isNotBlank(bindNo)) {
			this.payerBindCardInfo = getPayerBindInfo(map);
		}
		
		//获取收入方绑卡信息
		this.payeeBindCardInfo = getPayeeBindInfo(map);
		
		//风控校验
		newRiskCheck(map);
		
		//记录订单
		String tradeOrderId = recordOrder(request);		
		if (StringUtil.isNotBlank(tradeOrderId)) {
			map.put("tradeOrderId", tradeOrderId);
		}
		
		
		
		
		//调用支付中心下单
		return invokePayCore(map);
		
		//处理支付结果
		
		//通知风控（异步）
	}
	
	
	void newRiskCheck(Map<String, String> map){
		
		PayRiskService payRiskService = dubboConsumerFactory.getDubboClient("payRiskService"); 
		RiskParam param = new RiskParam();
		
		String channelId = map.get("channelId");
		String businessType = map.get("businessType");
		String productType = map.get("productType");
		String riskParams = map.get("riskParams");
		String orderId = map.get("orderId");
		String amount = map.get("amount");
		String srcChannel = map.get("srcChannel");
		boolean isUsePwd = false;
		String isUsePwdStr = map.get("isUsePwd");
		String bindNo = map.get("bindNo");
		String bankId = map.get("bankId");
		
		if(this instanceof TradeB2CService){
			if(productType.equals("1")){ //实物交易
				//增加判断快捷支付金额必须大于1毛
				int orderAmount = Integer.parseInt(amount);
				if(StringUtils.isNotBlank(bankId)){
					String startWith = bankId.substring(0, 1);
					if(startWith.equals("1") && orderAmount < 10){
						throw new BusinessException("订单交易金额小于0.1元");
					}
				}
				if (StringUtils.isNotBlank(bindNo) && orderAmount < 10) {
					throw new BusinessException("订单交易金额小于0.1元");
				}
			}
			
			if(productType.equals("1")){
				param.setTradeType(TradeType.PURCHASE_ENTITY);
			}else if(productType.equals("2")){//虚拟交易
				param.setTradeType(TradeType.PURCHASE_VIRTUAL);
			}
			
			if(isUsePwdStr != null && "1".equals(isUsePwdStr)){
				isUsePwd = true;
			}
			
			param.setReference(map.get("srcIp"));
		}else if(this instanceof TradeChargeService){
			param.setTradeType(TradeType.BALANCE_RECHARGE);
			param.setReference(map.get("reference"));
		}else if(this instanceof TradeTransferSrervice){
			
			int payType = Integer.parseInt(map.get("payType"));
			int receiverType = Integer.parseInt(map.get("receiverType"));
			if(payType == 1 && receiverType == 1){
				param.setTradeType(TradeType.TRANSFER_BERBON_BERBON);
			}else if(payType == 1 && receiverType == 2){
				param.setTradeType(TradeType.TRANSFER_BERBON_BANKCARD);
			}else if(payType == 2 && receiverType == 1){
				param.setTradeType(TradeType.TRANSFER_BANKCARD_BERBON);
			}else if(payType == 2 && receiverType == 2){
				param.setTradeType(TradeType.TRANSFER_BANKCARD_BANKCARD);
			}
			
			if(isUsePwdStr != null && "1".equals(isUsePwdStr)){
				isUsePwd = true;
			}
			
			param.setReference(map.get("reference"));
		}else if(this instanceof TradeWithdrawService){		
			int withdrawType = Integer.parseInt(map.get("withdrawType"));
			if((withdrawType == 2 || withdrawType == 3) && StringUtils.isBlank(map.get("bindNo"))){
				return;//返利金提现到余额
			}else{
				Integer	bindType = payerBindCardInfo.getBindType();
				if(withdrawType == 1 && bindType == 2){
					param.setTradeType(TradeType.WITHDRAW_BERBON_BANKCARD);
				}else if(withdrawType == 1 && bindType == 3){
					param.setTradeType(TradeType.WITHDRAW_BERBON_ALIPAY);
				}else if((withdrawType == 2 || withdrawType == 3) && bindType == 2){
					param.setTradeType(TradeType.WITHDRAW_PROFIT_BANKCARD);
				}else if((withdrawType == 2 || withdrawType == 3) && bindType == 3){
					param.setTradeType(TradeType.WITHDRAW_PROFIT_ALIPAY);
				}
			}
			param.setReference(map.get("reference"));
		}else{
			return;
		}
		
		if(param.getTradeType() != null){
			param.setBusinessType(businessType);
			param.setChannelId(channelId);
			param.setTradeAmount(Integer.parseInt(amount));
			param.setSrcChannel(srcChannel);
			if(productType != null){
				param.setProductType(Integer.parseInt(productType));
			}			
			
			param.setOrderId(orderId);
			
			if(this.payeeActInfo != null){
				param.setPayeeUserId(this.payeeActInfo.getUserId());
				param.setPayeeUserLevel(this.payeeActInfo.getActLevel());
				param.setPayeeUserType(this.payeeActInfo.getUserType());
			}
			if(this.payerActInfo != null){
				param.setPayerUserId(this.payerActInfo.getUserId());
				param.setPayerUserLevel(this.payerActInfo.getActLevel());
				param.setPayerUserType(this.payerActInfo.getUserType());
			}
		}
		
		param.setNoUsePwd(isUsePwd);
				
		payRiskService.checkRisk(param);
	}

	//1.验签
	void checkSign(Map<String, String> map){
		try {
			String orderId = map.get("orderId");
			
			String requestSign = map.get("sign");			
			ValidateUtil.isNotBlank(requestSign, "请求sign不能为空");
			ValidateUtil.strEqualLen(requestSign, 32, "请求sign必须为32位固定长度");
			map.remove("sign");
			
			String plain = ObjectUtil.createLinkString(map, true);		
			String signPrepare = plain + "&key=" + Constance.SIGN_KEY;
			String curSign = MD5Util.encrypt(signPrepare);
			
			if (!requestSign.equalsIgnoreCase(curSign)) {				
				logger.warn("["+orderId+"]请求验签错误");
				logger.warn("["+orderId+"]验签原串:"+plain);
				logger.warn("["+orderId+"]requestSign="+requestSign+",currentSign="+curSign);		
				throw new BusinessException("请求参数sign有误");
			}else {
				logger.info("["+orderId+"]验签通过");
			}			
		} catch (Exception e) {		
			throw new BusinessException("验签错误", e);
		}
	}
	
	//3.请求公用参数校验
	
	void checkPublicParam(Map<String, String> params){		
		
		String orderId = params.get("orderId");
		String attach = params.get("attach");
		String srcIp = params.get("srcIp");
		String srcChannel = params.get("srcChannel");
		String returnUrl = params.get("returnUrl");
		String notifyUrl = params.get("notifyUrl");
		String orderTime = params.get("orderTime");
		String expireTime = params.get("expireTime");
		String clientSourceType = params.get("clientSourceType");
		
		ValidateUtil.isNotBlank(orderId, "orderId不能为空");
		ValidateUtil.strMaxLen(orderId, 32, "orderId超过限制长度");
		
		if (attach != null) {
			ValidateUtil.strMaxLen(attach, 255, "attach超过限制长度");
		}
		
		ValidateUtil.isNotBlank(srcIp, "srcIp不能为空");
		ValidateUtil.isInet4Address(srcIp, "reference数据不合法");
		
		ValidateUtil.isNotBlank(srcChannel, "srcChannel不能为空");		
		ValidateUtil.isBetween(Integer.parseInt(srcChannel), 0, 4, "srcChannel数据不合法");
		
		if (!StringUtil.isBlank(returnUrl)) {
			ValidateUtil.isUrl(returnUrl, "returnUrl格式不正确");
		}
		
		if (!StringUtil.isBlank(notifyUrl)) {
			ValidateUtil.isUrl(notifyUrl, "notifyUrl格式不正确");
		}
		
		ValidateUtil.isNotBlank(orderTime, "orderTime不能为空");
		ValidateUtil.isDate(orderTime, "yyyyMMddHHmmss", "orderTime格式不正确");
		
		if (expireTime != null) {
			ValidateUtil.isDate(expireTime, "yyyyMMddHHmmss", "expireTime格式不正确");
		}
		
		if (!StringUtil.isBlank(clientSourceType)) {
			ValidateUtil.isBetween(Integer.parseInt(clientSourceType), 1, 7, "clientSourceType数据不合法");
		}
		
	}
	
	//校验不同交易各自的特定参数
	abstract void checkPrivateParam(Map<String, String> params);
	
	//判断订单已请求
	abstract boolean isRepeatOrder(Map<String, String> params);
	
	//记录订单信息
	abstract String recordOrder(TradeBaseRequest request);
	
	//获取支付者绑卡信息
	abstract UserBindCardDO getPayerBindInfo(Map<String, String> params); 
	
	//获取接收者绑卡信息
	abstract UserBindCardDO getPayeeBindInfo(Map<String, String> params); 
	
	//获取支付者的账户信息
	abstract UserActDO getPayerActInfo(TradeBaseRequest request);
	
	//获取接收者的账户信息
	abstract UserActDO getPayeeActInfo(TradeBaseRequest request);
	
	//调用支付中心下单
	abstract TradeResponse invokePayCore(Map<String, String> params);
	
	//处理支付结果
	abstract void handerPayCoreResult();

	
    public void newupdateRisk(TradeType tradeType,String orderId,String channelId,String businessType,
    		Integer productType,String payerUserId,String payeeUserId,
    		Integer tradeAmount,String srcChannel,String reference,String riskParams, boolean isNoUsePwd,
    		Date orderTime){
    	UserInfoDO payerUserInfo = null;
    	if(payerUserId != null){
    		payerUserInfo = userInfoService.findUserInfo(payerUserId);
    	}
    	UserInfoDO payeeUserInfo = null;
    	if(payeeUserId != null){
    		payeeUserInfo = userInfoService.findUserInfo(payeeUserId);
    	}
    	
    	
    	RiskParam param = new RiskParam();
    	param.setTradeType(tradeType);
    	
    	param.setReference(reference);
		param.setBusinessType(businessType);
		param.setChannelId(channelId);
		param.setTradeAmount(tradeAmount);
		param.setSrcChannel(srcChannel);
		param.setProductType(productType);
		param.setNoUsePwd(isNoUsePwd);
		param.setOrderTime(orderTime);
		
		
		param.setOrderId(orderId);
		
		if(payeeUserInfo != null){
			param.setPayeeUserId(payeeUserInfo.getUserId());
			param.setPayeeUserLevel(payeeUserInfo.getGrade());
			param.setPayeeUserType(payeeUserInfo.getUserType());
		}
		if(payerUserInfo != null){
			param.setPayerUserId(payerUserInfo.getUserId());
			param.setPayerUserLevel(payerUserInfo.getGrade());
			param.setPayerUserType(payerUserInfo.getUserType());
		}
		
		PayRiskService payRiskService = dubboConsumerFactory.getDubboClient("payRiskService"); 
		payRiskService.updateRisk(param);
    	
	}
    
}
